/*!
 *  jsMap v3.1.1
 *  Copyright (C) 2018-2019, ZhaoGang
 *  Released under the MIT license
 */
!(function ( global, factory ) {

    if ( typeof define === "function" && define.amd ) { 
        define( "jsmap", [ "jquery" ], factory );
    } else if ( typeof module !== "undefined" && typeof exports === "object" ) {
        module.exports = factory( require( "jquery" ) );
    } else {
        global.jsMap = factory( global.jQuery );
    }

})( typeof window !== "undefined" ? window : this, function ( $ ) {

	var UA = navigator.userAgent.toLowerCase();

	// 不支持 ie9- 的浏览器
	if ( UA.match( /msie (6|7|8|9)\.0/ ) ) {
		throw new Error( decodeURI( "jsMap%20%E4%B8%8D%E6%94%AF%E6%8C%81%20ie9-%20%E7%9A%84%E6%B5%8F%E8%A7%88%E5%99%A8" ) );
	}

	// 检测 jquery
	if ( typeof jQuery === "undefined" ) {
		throw new Error( decodeURI( "%E8%AF%B7%E5%9C%A8%20jsMap%20%E5%89%8D%E5%BC%95%E5%85%A5%20jQuery" ) );
	}
	var jqv = $.fn.jquery.split( "." );
    if ( ~~jqv[ 0 ] === 1 && ~~jqv[ 1 ] < 12 ) {
        throw new Error( decodeURI( "jsMap%20%E8%A6%81%E6%B1%82%20jQuery%20%E7%9A%84%E7%89%88%E6%9C%AC%E4%B8%8D%E8%83%BD%E4%BD%8E%E4%BA%8E%201.12.0" ) );
    }

    // 缓存 DOM
    var $document = $( document );
    var $window = $( window );
	var $tip = $( "" );

	// cache 存储
	var CacheJSON = {};

	// 检测移动设备
	var isMobile = !!( UA.match( /(ios|iphone|ipod|ipad|android)/ ) && "ontouchend" in document );

	// 创建 jsMap
	var jsMap = {
		version: "3.1.1",
		config: function ( selector, jsonData, options ) {

			// 默认配置
			var fill = {
				basicColor: "#3f99f9",
				hoverColor: "#0880ff",
				clickColor: "#006bde"
			}
			var defaults = {
				name: "china",
				width: 900,
				height: 500,
				stroke: {
					width: 1,
					color: "#f3f3f3"
				},
				fill: $.extend( true, {}, fill ),
				areaName: {
					show: false,
					size: 12,
					basicColor: "#333",
					clickColor: "#fff"
				},
				disabled: {
					color: "#bfbfbf",
					except: false,
					name: []
				},
				hide: [],
				multiple: false,
				tip: true,
				hoverCallback: $.noop,
				clickCallback: $.noop
			};
			var opt = $.extend( true, defaults, options );

			// 必须传入地图数据
			if ( !jsonData || !$.isPlainObject( jsonData ) ) {
				return;
			}

			// 暂无台湾省和南海诸岛的详细地图数据
			if ( opt.name === "taiwan" ) {
				console.warn( "jsMap%20%E6%8F%90%E7%A4%BA%EF%BC%9A%E5%BE%88%E6%8A%B1%E6%AD%89%EF%BC%8C%E6%9A%82%E6%97%A0%E5%8F%B0%E6%B9%BE%E7%9C%81%E7%9A%84%E8%AF%A6%E7%BB%86%E5%9C%B0%E5%9B%BE%E6%95%B0%E6%8D%AE%E3%80%82" );
				return;
			}
			if ( opt.name === "nanhaizhudao" ) {
				console.warn( "jsMap%20%E6%8F%90%E7%A4%BA%EF%BC%9A%E5%BE%88%E6%8A%B1%E6%AD%89%EF%BC%8C%E6%9A%82%E6%97%A0%E5%8D%97%E6%B5%B7%E8%AF%B8%E5%B2%9B%E7%9A%84%E8%AF%A6%E7%BB%86%E5%9C%B0%E5%9B%BE%E6%95%B0%E6%8D%AE%E3%80%82" );
				return;
			}

			// 取出要绘制的区域数据
			var mapData = jsonData[ opt.name ];
   
			var path = "",
				text = "",
				areaBox = [];

			$.each(mapData, function ( i, v ) {
				
				// 存储地区名称
				areaBox.push( i );

				// 绘制 path 路径
				path += '\
					<path \
						d="' + v.svg + '" \
						class="jsmap-' + i + '" \
						data-name="' + v.name + '" \
						data-id="' + i + '" \
						style="cursor:pointer;">\
					</path>\
				';

				// 设置文字
				text += '\
					<text \
						x="' + v.textPosition[ 0 ] + '" \
						y="' + v.textPosition[ 1 ] + '" \
						class="jsmap-' + i + '" \
						data-name="' + v.name + '" \
						data-id="' + i + '" \
						style="cursor:pointer;">' + v.name + '</text>\
				';
			});

			// 不显示区域名称
			if ( !opt.areaName.show ) { 
				text = "";
			}

			path = '<div \
				class="jsmap-svg-container" \
				style="\
					position:absolute;\
					top:0;\
					left:0;\
					padding:0;\
					margin:0;\
					transform-origin:center;\
					-webkit-user-select:none;\
					-moz-user-select:none;\
					-ms-user-select:none;\
					user-select:none;\
					-webkit-tap-highlight-color:transparent;"\
				>\
				<svg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 575 470">' + path + text + '</svg>\
			</div>';

			$( selector ).each(function () {
				var $this = $( this );

				// 记录当前指定的行内样式
				var cssCache = {
					width: this.style.width,
					height: this.style.height,
					padding: this.style.padding,
					position: this.style.position
				};
				$this.data( "__jsmap_csscache__", cssCache );

				// 给目标元素设置样式并添加数据存储
				if ( $this.css( "position" ) === "static" ) {
					$this.css( "position", "relative" );
				}
				$this.addClass( "jsmap-container" ).css({
					width: opt.width + "px",
					height: opt.height + "px",
					padding: 0
				}).empty().append( path ).data({
					__jsmap_jsondata__: jsonData,
					__jsmap_options__: options
				});

				var $container = $this.children(),
					$svg = $this.find( "svg" ),
					$path = $svg.find( "path" ),
					$text = $svg.find( "text" ),
					$pathText = $path.add( $text );

				$container.width( opt.width ).height( opt.height );

				if ( opt.multiple ) {
					$container.data( "__jsmap_multiple__", true );
				}

				$svg.attr({
					width: opt.width,
					height: opt.height
				}).css({
					position: "relative",
					overflow: "hidden",
					marginLeft: opt.name === "china" ? "-50px" : 0
				});

				$text.each(function () {

					// 如果 text 不是下列匹配的区域
					// 则禁用任何鼠标行为
					if ( !$( this ).attr( "data-id" ).match( /(shanghai|xianggang|aomen|nanhaizhudao|tianjin|beijing)/ ) ) {
						$( this ).css( "pointerEvents", "none" );
					}
				})

				// 隐藏指定的区域
				if ( Array.isArray( opt.hide ) && opt.hide.length ) {
					$.each(opt.hide, function ( i, v ) {

						// 支持汉字和全拼两种形式
						$pathText.filter( '[data-id="' + v + '"], [data-name="' + v + '"]' ).hide();
					})
				}

				var fillBasicColor = opt.fill.basicColor;

				// 填充色 - 统一设置
				if ( typeof fillBasicColor === "string" ) {
					$path.attr({
						fill: fillBasicColor,
						"data-fill": fillBasicColor
					});
				}

				// 填充色 - 单独设置
				if ( $.isPlainObject( fillBasicColor ) && !$.isEmptyObject( fillBasicColor ) ) {
					$path.attr({
						fill: "#3f99f9",
						"data-fill": "#3f99f9"
					});
					$.each(fillBasicColor, function ( i, v ) {
						$path.filter( ".jsmap-" + i ).attr({
							fill: v,
							"data-fill": v
						});
					})
				}

				// 给 path 添加过渡时间
				var timer = window.setTimeout(function () {
					$path.css( "transition", ".2s" );
					window.clearTimeout( timer );
				}, 13);

				// 描边
				$path.attr({
					stroke: opt.stroke.color,
					"stroke-width": opt.stroke.width
				});

				// 文字颜色大小
				if ( opt.areaName.show ) {
					$text.attr({
						fill: opt.areaName.basicColor,
						"font-size": opt.areaName.size
					});
				}

				// 禁用指定的区域
				var disabledName = opt.disabled.name;
				if ( Array.isArray( disabledName ) && disabledName.length ) {
					function setDisabled ( selector ) {
						$( selector ).addClass( "jsmap-disabled" ).css( "cursor", "not-allowed" ).not( "text" ).attr( "fill", opt.disabled.color );
					}

					// 反选
					if ( opt.disabled.except ) {
						var result = [];
						$.each(disabledName, function ( i, v ) {

							// 支持汉字和全拼两种形式
							result.push( !v.match( /[a-z]/ ) ? $path.filter( '[data-name="' + v + '"]' ).attr( "data-id" ) : v );
						})

						// 克隆一个含有地区名称的数组
						var cloneNames = $.extend( true, [], areaBox );

						// 进行反选的筛选操作
						$.each(result, function ( i, v ) {
							cloneNames.splice( cloneNames.indexOf( v ), 1 );
						})

						// 设置禁用效果
						$.each(cloneNames, function ( i, v ) {
							setDisabled( $this.find( ".jsmap-" + v ) );
						})
					} else {
						$.each(disabledName, function ( i, v ) { 

							// 设置禁用效果
							setDisabled( $this.find( !v.match( /[a-z]/ ) ? ( '[data-name="' + v + '"]' ) : ( ".jsmap-" + v ) ) );
						})
					}
				}

				// 悬浮提示层
				if ( opt.tip ) {
					if ( !$( "#jsmap-tip" ).length ) {
						$( "body" ).append( '<section \
							id="jsmap-tip" \
							style="\
							position:absolute;\
							top:0;\
							left:0;\
							z-index:999;\
							display:inline-block;\
							width:auto;\
							height:auto;\
							overflow:hidden;\
							display:none;"\
						></section>' );
						$tip = $( "#jsmap-tip" );
					}
				}

				// 事件集合
				$.each(areaBox, function ( i, v ) {
					$this.find( ".jsmap-" + v ).on({
						mouseenter: function () {
							if ( isMobile ) {
								return;
							}

							var _this = $( this );

							// 如果此区域被禁用
							// 则无任何事件
							if ( _this.hasClass( "jsmap-disabled" ) ) {
								return;
							}

							// 鼠标悬浮时的填充色 ( 未被点击过的情况下 )
							if ( !_this.hasClass( "jsmap-clicked" ) ) {

								// 克隆一个含有地区名称的数组
								var cloneAllName = $.extend( true, [], areaBox );

								if ( typeof opt.fill.hoverColor === "string" ) {
									_this.filter( "path" ).attr( "fill", opt.fill.hoverColor );
								}

								if ( $.isPlainObject( opt.fill.hoverColor ) && !$.isEmptyObject( opt.fill.hoverColor ) ) {
									$.each(opt.fill.hoverColor, function ( i, v ) {
										_this.filter( ".jsmap-" + i ).attr( "fill", v );
										cloneAllName.splice( cloneAllName.indexOf( i ), 1 );
									})

									// 未特殊设置的地区仍保持默认配置色
									$.each(cloneAllName, function ( i, v ) {
										_this.filter( ".jsmap-" + v ).attr( "fill", fill.hoverColor );
									})
								}
							}

							// 悬浮回调事件
							opt.hoverCallback( _this.attr( "data-id" ), _this.attr( "data-name" ) );

							// 悬浮提示框
							if ( opt.tip ) {

								// 为 true 时显示地区的汉字名称
								if ( opt.tip === true ) {
									$tip.html( '<div \
										style="\
											padding:10px 12px;\
											color:#fff;\
											font-size:14px;\
											text-align:center;\
											border-radius:4px;\
											border:#777 solid 1px;\
											background:rgba(0,0,0,.75);"\
									>' + _this.attr( "data-name" ) + '</div>' );
								}

								// 是函数时可显示自定义内容
								// 函数的参数包含了地区的全拼和汉语名称
								if ( $.isFunction( opt.tip ) ) {
									$tip.html( opt.tip( _this.attr( "data-id" ), _this.attr( "data-name" ) ) );
								}

								// 悬浮移动事件
								$document.on("mousemove", function ( event ) {
									var x = event.pageX + 12 + "px",
										y = event.pageY + 12 + "px";
									$tip.css( "transform", "translate3d(" + x + ", " + y + ", 0)" );
									$tip.show();
								})
							}
						},
						mouseleave: function () {
							if ( isMobile ) {
								return;
							}

							var _this = $( this );

							// 如果此区域被禁用
							// 则无任何事件
							if ( _this.hasClass( "jsmap-disabled" ) ) {
								return;
							}

							// 恢复原始填充色 ( 未被点击过的情况下 )
							if ( !_this.hasClass( "jsmap-clicked" ) ) {
								_this.filter( "path" ).attr( "fill", _this.attr( "data-fill" ) );
							}

							// 悬浮框内容清空并恢复位置
							if ( opt.tip ) {
								$tip.empty().hide().css( "transform", "translate3d(0, 0, 0)" );
								$document.off( "mousemove" );
							}
						},
						click: function () {
							var _this = $( this );

							// 如果此区域被禁用
							// 则无任何事件
							if ( _this.hasClass( "jsmap-disabled" ) ) {
								return;
							}

							var id = _this.attr( "data-id" );

							// 点击回调事件
							// 函数的参数包含了地区的全拼和汉语名称
							opt.clickCallback( _this.attr( "data-id" ), _this.attr( "data-name" ) );

							// 点击后的填充色
							if ( opt.fill.clickColor === false ) {
								return;
							} else {

								// 克隆一个含有地区名称的数组
								var cloneAllName = $.extend( true, [], areaBox );

								if ( typeof opt.fill.clickColor === "string" ) {
									_this.filter( "path" ).attr( "fill", opt.fill.clickColor );
								}
								if ( $.isPlainObject( opt.fill.clickColor ) && !$.isEmptyObject( opt.fill.clickColor ) ) {
									$.each(opt.fill.clickColor, function ( i, v ) {
										_this.filter( ".jsmap-" + i ).attr( "fill", v );
										cloneAllName.splice( cloneAllName.indexOf( i ), 1 );
									})

									// 未特殊设置的地区仍保持默认配置色
									$.each(cloneAllName, function ( i, v ) {
										_this.filter( ".jsmap-" + v ).attr( "fill", fill.clickColor );
									})
								}
							}

							// 点击后的文字颜色
							if ( opt.areaName.clickColor !== false ) {
								if ( opt.areaName.show ) {
									var $el = $this.find( "text.jsmap-" + _this.attr( "data-id" ) );
									$el.attr( "fill", opt.areaName.clickColor );
									if ( !opt.multiple ) {
										$el.siblings( "text" ).attr( "fill", opt.areaName.basicColor );
									}
								}
							}

							// 单选
							if ( !opt.multiple ) {
								_this.addClass( "jsmap-clicked" );
								$pathText.not( ".jsmap-" + id ).not( ".jsmap-disabled" ).removeClass( "jsmap-clicked" ).each(function () {
									$( this ).attr( "fill", $( this ).attr( "data-fill" ) );
								});
							} else {

								// 多选
								_this.toggleClass( "jsmap-clicked" );
								if ( !_this.hasClass( "jsmap-clicked" ) ) {
									_this.attr( "fill", _this.attr( "data-fill" ) );
								}
							}
						}
					});
				})
			})
		},
		refresh: function ( selector ) {
			$( selector ).each(function () {
				var $this = $( this );
				var cache_1 = $this.data( "__jsmap_jsondata__" ),
					cache_2 = $this.data( "__jsmap_options__" );
				if ( cache_1 && cache_2 && $this.find( "div.jsmap-svg-container > svg" ).length ) {
					jsMap.config( $this, cache_1, cache_2 );
				}
			})
		},
		remove: function ( selector ) {
			$( selector ).each(function () {
				var $this = $( this ),
					_this = this;
				var getCssCache = $this.data( "__jsmap_csscache__" );
				if ( getCssCache ) {
					$.each(getCssCache, function ( i, v ) {
						if ( v ) {
							_this.style[ i ] = v;
						} else {
							_this.style.removeProperty( i );
						}
					})
				}
				$this.removeClass( "jsmap-container" )
					.removeData( "__jsmap_csscache__ __jsmap_jsondata__ __jsmap_options__" )
					.children()
					.remove();
			})
		},
		multipleValue: function ( selector, options ) {
			var defaults = {
				type: "array"
			};
			var opt = $.extend( {}, defaults, options );

			var $target = $( selector ).first().children( ".jsmap-svg-container" );
			if ( $target.data( "__jsmap_multiple__" ) ) {
				var $clicked = $target.find( ".jsmap-clicked" );
				if ( opt.type === "array" ) {
					var a = [], 
						b = [];
					$clicked.each(function () {
						a.push( $( this ).attr( "data-id" ) );
						b.push( $( this ).attr( "data-name" ) );
					});
					return [ a, b ];
				} 
				if ( opt.type === "object" ) {
					var obj = {};
					$clicked.each(function () {
						obj[ $( this ).attr( "data-id" ) ] = $( this ).attr( "data-name" );
					})
					return obj;
				}
			} else {
				return opt.type === "array" ? [] : {};
			}
		},
		preloadJSON: function ( obj, callback ) {
			if ( $.isPlainObject( obj ) && !$.isEmptyObject( obj ) ) {
				var cache = {};
				var totalSize = Object.keys( obj ).length;

				// 定义 deferred 数组
				var deferredArray = [];
				
				// 定义请求成功的文件数
				var successSize = 0;

				// 获取 json
				$.each(obj, function ( i, v ) {
					var deferred = $.Deferred();
					deferredArray.push( deferred );
					(function ( def ) {
						$.getJSON( v ).done(function ( json ) {
							cache[ i ] = json;
							successSize++;
						}).always(function () {
							def.resolve();
						});
					})( deferred );
				})

				// 添加缓存
				$.when.apply( this, deferredArray ).done(function () {
					$window.data({
						__jsmap_cache_total_size__: totalSize,
						__jsmap_cache_success_size__: successSize,
						__jsmap_cache_fail_size__: totalSize - successSize,
						__jsmap_cache_json__: cache
					});
					CacheJSON = {
						total: totalSize,
						success: successSize,
						fail: totalSize - successSize,
						json: cache
					};
					if ( $.isFunction( callback ) ) {
						callback( CacheJSON );
					}
				})
			}
		},
		getPreloadJSON: function ( name ) {
			name = $.trim( name );
			return !name ? CacheJSON : CacheJSON.json[ name ];
		}
	};

	// 封存 jsMap
	!(function freezeJsMap ( obj ) {
        Object.freeze( obj );
        $.each(Object.keys( obj ), function ( i, v ) {
            if ( typeof obj[ v ] === "object" ) {
                freezeJsMap( obj[ v ] );
            }
        })
    })( jsMap );

	return jsMap;

});